# This file contains all the image operations performed by AugIM.

import scavenger

##### BLUR #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def blur(image_data, factor = 1.0):
    from PIL import Image, ImageEnhance
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    factor = 1.0 - factor
    new_image = ImageEnhance.Sharpness(pil_image).enhance(factor)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### SHARPEN #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def sharpen(image_data, factor = 1.0):
    from PIL import Image, ImageEnhance
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    factor = 1.0 + factor
    new_image = ImageEnhance.Sharpness(pil_image).enhance(factor)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### BRIGHTNESS #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def brightness(image_data, factor):
    from PIL import Image, ImageEnhance
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    new_image = ImageEnhance.Brightness(pil_image).enhance(factor)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### COLOR #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def color(image_data, factor):
    from PIL import Image, ImageEnhance
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    new_image = ImageEnhance.Color(pil_image).enhance(factor)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### CONTRAST #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def contrast(image_data, factor):
    from PIL import Image, ImageEnhance
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    new_image = ImageEnhance.Contrast(pil_image).enhance(factor)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### INVERT #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def invert(image_data):
    from PIL import Image, ImageOps
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    new_image = ImageOps.invert(pil_image)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### FLIP HORIZONTAL #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def flip_horizontal(image_data):
    from PIL import Image
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    new_image = pil_image.transpose(Image.FLIP_TOP_BOTTOM)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()
    
##### FLIP VERTICAL #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def flip_vertical(image_data):
    from PIL import Image
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    new_image = pil_image.transpose(Image.FLIP_LEFT_RIGHT)
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### ROTATE #####
@scavenger.cprofilescavenge('len(#0)', store = True)
def rotate(image_data, angle):
    from PIL import Image
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)
    new_image = pil_image.rotate(int(angle))
    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### SCALE #####
@scavenger.cprofilescavenge('len(#0) / 2', store = True)
def scale(image_data, size, maintain_aspect = True, method = 1): # 1 = Image.ANTIALIAS
    from PIL import Image
    from StringIO import StringIO
    sio = StringIO(image_data)
    pil_image = Image.open(sio)

    # This function calculates the aspect maintaining size that the image
    # should be resized to.
    def adjust_size_to_maintain_aspect(original_size, desired_size):
        scale_ = float(desired_size[0])/original_size[0]
        if original_size[1] * scale_ <= desired_size[1]:
            height = int(original_size[1] * scale_)
            if height > desired_size[1]:
                height = desired_size[1]
            return (desired_size[0], height)
        else:
            scale_ = float(desired_size[1])/original_size[1]
            width = int(original_size[0] * scale_)
            if width > desired_size[0]:
                width = desired_size[0]
            return (width, desired_size[1])
    
    if maintain_aspect:
        size = adjust_size_to_maintain_aspect(pil_image.size, size)
    
    # Scale the image.
    new_image = pil_image.resize(size, method)

    sio = StringIO()
    new_image.save(sio, pil_image.format, quality=95)
    return sio.getvalue()

##### Send image to Picasa web #####
@scavenger.cprofilescavenge('0')
def picasa_upload(image_data, username, password, album = 'AugIM Album', title = 'unnamed', description = '', content_type='image/jpeg'):
    from StringIO import StringIO
    import gdata.photos.service
    image = StringIO(image_data)
    # login
    try:
        gd_client = gdata.photos.service.PhotosService()
        gd_client.email = username
        gd_client.password = password
        gd_client.source = 'PicasaClientLib-test-code'
        gd_client.ProgrammaticLogin()
    except Exception, e:
        raise Exception('Picasa: Error logging in. %s'%e.message)

    # sanity check wrt. album_name - if None or unknown, create a new album
    try:
        feed = gd_client.GetUserFeed(user=username)
        def known_album(x): return album == x.title.text
        seen_it = filter(known_album, feed.entry)
        if not seen_it:
            entry = gd_client.InsertAlbum(title=album, summary=None)
            album = entry.title.text
    except Exception, e:
        raise Exception('Picasa: Error locating/creating album. %s'%e.message)

    # note: Spaces in album names cannot be handled programmatically correct
    album = album.replace(" ", "")

    # upload the file
    try:
        album_url = '/data/feed/api/user/%s/album/%s' % (username, album)
        gd_client.InsertPhotoSimple(album_url, title, description, image, content_type = content_type)
    except Exception, e:
        raise Exception('Picasa: Error uploading image. %s'%e.message)
    return True

##### Send email #####
@scavenger.cprofilescavenge('0')
def send_mail(server, port, sender, recipient, subject, message, username = '', password = '', attachment = '', mime_type = ''):
    from StringIO import StringIO
    from smtplib import SMTP
    from MimeWriter import MimeWriter
    import base64

    # Build the message header.
    message_obj = StringIO()
    writer = MimeWriter(message_obj)
    writer.addheader('Subject', subject)
    writer.startmultipartbody('mixed')
    part = writer.nextpart()
    
    # Add the message body.
    body = part.startbody('text/plain')
    body.write(message)
    
    # And (optionally) the attachment.
    if attachment != '':
        part = writer.nextpart()
        part.addheader('Content-Transfer-Encoding', 'base64')
        body = part.startbody(mime_type) 
        base64.encode(StringIO(attachment), body)
    
    # Finish the message.
    writer.lastpart()
    
    # Send the mail (and authenticate if necessary).
    smtp = SMTP(server, port)
    if username != '':
        smtp.login(username, password)
    smtp.sendmail(sender, recipient, message_obj.getvalue())
    smtp.quit()
    return True